/*
 * Copyright (C) 2005 Dmitri Maximovich <maxim@md.pp.ru>
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 */
function initCc() {
	showCcIcon("error");
	showCcTooltip("Waiting for status update...");

    // load prefs
    this.prefs = new Prefs();
    prefs.load();

	// start update manager
	ccUpdateManager();
}

function ccLog(aMessage) {
	if (prefs.debug) {
		var consoleService = Components.classes['@mozilla.org/consoleservice;1'].getService(Components.interfaces.nsIConsoleService);
		consoleService.logStringMessage("ccMonitor: "+aMessage);
	}
}

function ccUpdateManager() {
	ccLog("ccUpdateManager() start");
	try {
		var now = (new Date()).getTime();
		if ((now - prefs.lastUpdate) > prefs.refresh) {
			getCcData();
			prefs.lastUpdate = (new Date()).getTime();
		}
	}
	catch(e) {
		ccLog("ccUpdateManager() exception: "+e);
	}

	// schedule to re-run self every 10 sec
	setTimeout("ccUpdateManager()", 10000);
}

function getCcData() {
	ccLog("getCcData(): sending request to "+this.prefs.url);
	var request = new XMLHttpRequest();
	request.onload = function() {
		showCc(request);
	};

	request.open("GET", this.prefs.url);
	// username/password
	//request.open("GET", url, true, "maxim", "qwe123");
	request.setRequestHeader("User-Agent","Mozilla/4.0 (compatible; CC Monitor)");
	request.send(null);
}

function showCc(request) { 
	ccLog("showCc(): begin");

	ccRemoveMenuProjects();
	if (request.readyState != 4 || request.status != 200) {
		// status is not complete
		showCcIcon("error");
		showCcTooltip("Status request failure. Check URL in Options dialog. (HTTP status: "+request.status+")");
		return;
	}

	try {
		ccLog("showCc(): parse result");
		// parse result and store in global var
		 this.cc = new CCm(request.responseText, this.prefs);

		// change icon
		showCcIcon(cc.allPassed ? "success" : "failure");
		// show tooltip
		showCcTooltipFromModel(cc);
		// projects menu
		ccAddMenuProjects(cc);
	}
	catch (e) {
		ccLog("Exception occured: "+e);
		showCcIcon("error");
		showCcTooltip("Exception: "+e);
		ccRemoveMenuProjects();
	}
	ccLog("showCc(): end");
}

function showCcIcon(aType) {
	var ccButton = document.getElementById('cc-status');
	if (ccButton != null) {
		ccButton.setAttribute("status", aType);
	}
}

function showCcTooltip(aLine) {
	removeTooltip();
	
    var tooltip = document.getElementById('cc-tooltip');
    if (tooltip == null) {
    	ccLog("Can't create tooltip");
    }

    var box = document.createElement("vbox");
    box.setAttribute("id", "cc-vbox");

    var label = document.createElement("label");
    label.setAttribute("value", aLine);
   	label.setAttribute("style", "margin:0px");

	box.appendChild(label);
	tooltip.appendChild(box);
}

function removeTooltip() {
    var old = document.getElementById('cc-vbox');
    if (old != null) {
	    old.parentNode.removeChild(old);
	}
}

function showCcTooltipFromModel(cc) {
	removeTooltip();

    var tooltip = document.getElementById('cc-tooltip');
    
    if (tooltip == null) {
    	ccLog("Can't create tooltip");
    }
    
    var box = document.createElement("vbox");
    box.setAttribute("id", "cc-vbox");

	var grid = document.createElement("grid");
	box.appendChild(grid);
	
	var columns = document.createElement("columns");
	columns.appendChild(document.createElement("column"));
	columns.appendChild(document.createElement("column"));
	columns.appendChild(document.createElement("column"));
	// show activity column for .Net projects
	if (cc.type == "N") {
		columns.appendChild(document.createElement("column"));
	}
	grid.appendChild(columns);	
	
	var rows = document.createElement("rows");
	grid.appendChild(rows);	

	var maxNameLen = cc.maxNameLen;
	// limit length
	if (maxNameLen > prefs.maxProjectNameLen) {
		maxNameLen = prefs.maxProjectNameLen;
	}
	
	for(i = 0; i < cc.projects.length; i++) {
		var project = cc.projects[i];
		var row = ccConstructRow(cc.type, project, maxNameLen);		
		rows.	appendChild(row);
	}

    // add generated, span all columns so add directly to the rows
	var label = document.createElement("label");
	label.setAttribute("value", cc.generated+"/"+formatDate(cc.created, "HH:mm:ss"));
   	label.setAttribute("style", "margin:0px; text-align: right;  font-size: smaller");
	rows.	appendChild(label);

	// show
	tooltip.appendChild(box);
}

// construct one tooltip row
function ccConstructRow(type, project, maxNameLen) {
	const margin = "margin:0px 10px 0px 0px; ";
	const stylePassed = margin+"color:green;"
	const styleFailed = margin+"color:red;"
	
	var row = document.createElement("row");

	// project name		
	var label = document.createElement("label");
	label.setAttribute("value", pad(project.name, maxNameLen));
    label.setAttribute("style", project.passed ? stylePassed : styleFailed);
	row.appendChild(label);

	// just separator
	label = document.createElement("label");
    if (!project.passed) {
		label.setAttribute("value", "*");
        label.setAttribute("style", styleFailed);
    }
	row.appendChild(label);
		
	// last run
	label = document.createElement("label");
	label.setAttribute("value", project.lastRun);
    label.setAttribute("style", project.passed ? stylePassed : styleFailed);
	row.appendChild(label);

	// show activity for .Net project
	if (type == "N") {
		label = document.createElement("label");
		label.setAttribute("value", project.activity);
	    label.setAttribute("style", project.passed ? stylePassed : styleFailed);
		row.appendChild(label);
	}
	
	return row;
}

function ccGotoDetails(event) {
	var url = this.prefs.url;
    // goto jmx page if Ctrl is pressed
	if (event != null && event.ctrlKey) {
		if (this.prefs.jmxUrl != "") {
			url = this.prefs.jmxUrl;
		}
	}
	// if RSS, than strip /rss from the end of the URL to go to the CC page
	var pos = url.toLowerCase().indexOf("/rss");
	if (pos > 0) {
	 	url = url.substr(0, pos+1);
	}
	ccGoto(url);
}

function ccGoto(url) {
	if (navigator.userAgent.search(/Thunderbird/gi) != -1) {
		// Thunderbird
		var messenger = Components.classes["@mozilla.org/messenger;1"].createInstance();         
		messenger = messenger.QueryInterface(Components.interfaces.nsIMessenger);
		messenger.launchExternalURL(url);  
	}
	else {
		// Firefox
		// open in new tab
	    const newTab = getBrowser().addTab(url);
		getBrowser().selectedTab = newTab;
		// open in new Window
		//window.open(this.prefs.url);
	}
}

// pad with spaces
function pad(val, len) {
	if (val.length > len) {
		return val.substring(0, len - 3)+"...";
	}
	return (val+"                         ").substring(0, len);
}


/////////////////////////////////////////////////////////////////////////////
function ccAddMenuProjects(cc) {
    try {
	    var menu = document.getElementById('cc-popup-projects');
	    if (menu == null) {
	    	ccLog("cannot get reference to projects menu");
	    	return;
	    }
	    
	    //set none
	    if (cc.projects.length == 0) {
	      item = document.createElement("menuitem");
	      item.setAttribute("label", "No projects");
	      item.setAttribute("disabled", true);
	      menu.appendChild(item);
	      return;
	    };  
	    
	    if (this.prefs.jmxUrl == "") {
	      item = document.createElement("menuitem");
	      item.setAttribute("label", "JMX disabled");
	      item.setAttribute("disabled", true);
	      menu.appendChild(item);
	      return;
	    };  
	
	    if (cc.type == "N") {
	      item = document.createElement("menuitem");
	      item.setAttribute("label", "JMX supported only in Java version of CruiseControl");
	      item.setAttribute("disabled", true);
	      menu.appendChild(item);
	      return;
	    };  

	    //set for one or more
	    for (var i = 0; i < cc.projects.length; i++) {
	      var project = cc.projects[i];
	      item = document.createElement("menu");
	      item.setAttribute("label", project.name);
	      //  item.setAttribute("checked", "true");
	      item.setAttribute("style", project.passed ? "color: green;" : "color: red;");
	
		  // add commands submenu
		  var popup = document.createElement("menupopup");
	      ccAddProjectCommands(popup, project);
	      item.appendChild(popup);
	
	      menu.appendChild(item);
	    }
    }
    catch (e) {
    	ccLog("Error while building projects menu: "+e);
    }
}

function ccRemoveMenuProjects() {
    var menu = document.getElementById('cc-popup-projects');
    if (menu == null) {
    	ccLog("cannot getreference to projects menu");
    	return;
    }
    
    // remove childrens
    while (menu.hasChildNodes()) {
      menu.removeChild(menu.lastChild);
    }
}
  
function ccSelectMenuProject(projectName, action) {
    var msg = "Executing '"+action+"' for '"+projectName+"'";
    //alert(msg);
    ccLog(msg);
    
  try {
	  var request = new XMLHttpRequest();
	  request.onload = function() {
	      try {
		      //alert("Request status: "+request.status);
		      //alert(request.responseText);

              if (request.readyState != 4 || request.status != 200) {
					// status is not complete
					alert("Error invoking JMX action. HTTP status: "+request.status);
					return;
              }
			  
			  // see doc http://www.xulplanet.com/references/objref/Document.html
			  // we cannot use responseXML because CC JMX doesn't give us Content-type: text/xml even when using template=identity???
			  var xmlParser = new DOMParser();
		      var xmlDocument = xmlParser.parseFromString(request.responseText, 'text/xml');
		      
		      // this is Node
		      var operationResult = xmlDocument.documentElement.firstChild;
			  var result = operationResult.getAttribute("result");
			  if (result == "success") {
				alert("Successfully invoked JMX operation: '"+action+"' on '"+projectName+"'");
			  }
			  else {
			    var errorMsg = operationResult.getAttribute("errorMsg");
				alert("Error invoking JMX operation: '"+action+"' on '"+projectName+"': "+errorMsg);
			  }
		   }
		   catch(e) {
		   		alert("Error processing JMX call response: "+e);
		   }
	  };
	  //encodeURIComponent("");
	  var url =  this.prefs.jmxUrl+"/invoke?template=identity&operation="+action+"&objectname=CruiseControl+Project%3Aname%3D"+projectName;
	  ccLog(url);
	  
	  request.open("GET", url, false);
	  request.send(null);
    }
	catch (e) {
		alert("Error "+msg+": Make sure that JMX URL is correct and pointing to the same CruiseControl server as status page URL in Options dialog.");
		ccLog("Error "+msg+": "+e);
	}
    
}

// add commands submenu
function ccAddProjectCommands(parent, project) {
	var item;

    item = document.createElement("menuitem");
    item.setAttribute("label", "Build");
    item.setAttribute("oncommand", 'ccSelectMenuProject("'+project.name+'", "build");');
	parent.appendChild(item);

    item = document.createElement("menuitem");
    item.setAttribute("label", "Pause");
    item.setAttribute("oncommand", 'ccSelectMenuProject("'+project.name+'", "pause");');
	parent.appendChild(item);

    item = document.createElement("menuitem");
    item.setAttribute("label", "Resume");
    item.setAttribute("oncommand", 'ccSelectMenuProject("'+project.name+'", "resume");');
	parent.appendChild(item);
}

window.addEventListener("load", function() {initCc();}, false);
